﻿using Dapper;
using DevExpress.Data;
using DevExpress.Data.Filtering;
using DevExpress.Data.Linq;
using DevExpress.Data.Linq.Helpers;
using DevExpress.ExpressApp;
using System.Linq.Dynamic.Core;
using System.Text.Json.Nodes;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Users;
using YAKEJI.Abp.Database;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.Exams;
using YAPACS.Organizations;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Services.Dtos;
using YAPACS.RisServer.Workflows.ArchiveExam;
using YAPACS.Workflows;

namespace YAPACS.RisServer.Services;

public class ExamListService(IRepository<ExamFilter, Guid> filterRepository,
    IRepository<ApplicationUser, Guid> userRepository, ICurrentUserOrganization currentUserOrganization,
    IRepository<Exam, Guid> examRepository, IServiceProvider serviceProvider, IRepository<ExamFlag, Guid> examFlagRepository, ICurrentUser currentUser,
    IGetArchiveExamList getArchiveExamList) : DomainService, IExamListService, ITransientDependency
{
    private readonly ICurrentUser _currentUser = currentUser;
    private readonly IRepository<ExamFilter, Guid> _filterRepository = filterRepository;
    private readonly IRepository<ApplicationUser, Guid> _userRepository = userRepository;
    private readonly ICurrentUserOrganization _currentUserOrganization = currentUserOrganization;
    private readonly IRepository<Exam, Guid> _examRepository = examRepository;
    private readonly IServiceProvider _serviceProvider = serviceProvider;
    private readonly IRepository<ExamFlag, Guid> _examFlagRepository = examFlagRepository;
    private readonly IGetArchiveExamList _getArchiveExamList = getArchiveExamList;

    public async Task<WorkflowOutput> GetListByFilterAsync(DataGridRequest request, CriteriaOperator criteriaOperator,
        IWorkflow expressionWorkflow, IWorkflow getHeadersWorkflow, IWorkflow getRowStyleWorkflow = null,
        IWorkflow getDefaultFilterWorkflow = null, ExamFilterType examFilterType = ExamFilterType.Appointment)
    {
        //获取查询表达式
        ExamFilter examFilter = null; ExamFlag examFlag = null;
        var input = new WorkflowInput { { "Input", request.UserData } };
        if (request.UserData != null && request.UserData.Count > 0)
        {
            const string key = "Output";
            var workflowOutput = await expressionWorkflow.InvokeAsync(input);
            if (!workflowOutput.Success)
            {
                throw new Exception(workflowOutput.Error);
            }
            if (input.ContainsKey(key) && input.GetValueOrDefault(key) is CriteriaOperator criteria)
            {
                criteriaOperator = CriteriaOperator.And(criteriaOperator, criteria);
            }
        }
        else
        {
            if (!request.FilterId.Equals(default))
            {
                examFilter = await _filterRepository.FindAsync(request.FilterId);
                if (examFilter == null)
                {
                    //查询收藏
                    examFlag = await _examFlagRepository.GetAsync(request.FilterId);
                }
            }
            else
            {
                if (_currentUser.IsAuthenticated)
                {
                    var user = await _userRepository.GetAsync(_currentUserOrganization.UserId);
                    examFilter = user.GetDefaultFilter(_currentUserOrganization.UserGroupId.Value, examFilterType);
                }
            }
            criteriaOperator = CriteriaOperator.And(criteriaOperator, await GetFilter(getDefaultFilterWorkflow, examFilter));
            if (examFlag != null)
            {
                criteriaOperator = CriteriaOperator.And(criteriaOperator, CriteriaOperator.FromLambda<Exam>(e => e.ExamFlags.Any(f => f == examFlag)));
            }
        }
        //获取表头
        var columnsOutput = await getHeadersWorkflow.InvokeAsync(new WorkflowInput { { "Filter", examFilter } });
        if (!columnsOutput.Success)
        {
            throw new Exception(columnsOutput.Error);
        }
        string columnsString = ExtendColumnItem(columnsOutput.Data as string);

        var columns = columnsString.Deserialize<Column[]>();
        //获取行样式
        var rowStylesOutput = new WorkflowOutput();
        if (getRowStyleWorkflow != null)
        {
            rowStylesOutput = await getRowStyleWorkflow.InvokeAsync(new WorkflowInput { { "Filter", examFilter } });
            if (!rowStylesOutput.Success)
            {
                throw new Exception(rowStylesOutput.Error);
            }
        }


        //根据获取到的表头查询列表
        var selectStr = columns.GetColumnString();
        //获取排序
        var archiveRequest = request.Serialize().Deserialize<DataGridRequest>();
        if (request.Sort != null && request.Sort.Count > 0)
        {
            foreach (var sort in request.Sort)
            {
                var column = columns.Where(e => e.DataField == sort.Selector).FirstOrDefault();
                if (column != null)
                {
                    if (!string.IsNullOrWhiteSpace(column.Order))
                    {
                        sort.Selector = column.Order;
                    }
                    else if (!string.IsNullOrWhiteSpace(column.Property))
                    {
                        sort.Selector = column.Property;
                    }
                }
            }
        }
        else
        {
            request.Sort = new List<DataGridRequest.SortModel>() { new() { Selector = "Oid", Desc = true } };
        }
        var orders = request.Sort.Select(e => new ServerModeOrderDescriptor(new OperandProperty(e.Selector), e.Desc));
        var query = (await _examRepository.GetQueryableAsync()).AppendWhere(new CriteriaToExpressionConverter(), criteriaOperator)
            .MakeOrderBy(new CriteriaToExpressionConverter(), orders);
        var skipQuery = CriteriaToQueryableExtender.Skip(query, request.Skip);
        var list = CriteriaToQueryableExtender.Take(skipQuery, request.Take).Select(selectStr).ToDynamicList();
        //获取总行数
        var count = CriteriaToQueryableExtender.Count(query);
        if (request.Take - list.Count >= 0)
        {
            request.Take -= list.Count;
            if (request.Skip > 0)
            {
                request.Skip -= count;
                if (request.Skip < 0)
                {
                    request.Skip = 0;
                }
            }
        }
        input["Columns"] = columns;
        input["DataGridRequest"] = request;
        var archiveList = await _getArchiveExamList.InvokeAsync(input);
        if (archiveList.Success)
        {
            var dataGrid = (DataGridDto)archiveList.Data;
            list.AddRange((IEnumerable<dynamic>)dataGrid.Rows);
            count += (int)dataGrid.TotalCount;
        }
        return new WorkflowOutput()
        {
            Success = true,
            Data = new DataGridDto()
            {
                Columns = columnsOutput.Data,
                RowStyles = rowStylesOutput.Data,
                Rows = list,
                TotalCount = count
            }
        };
    }
    private async Task<CriteriaOperator> GetFilter(IWorkflow getDefaultFilterWorkflow, ExamFilter examFilter)
    {
        CriteriaOperator criteria = null;

        if (getDefaultFilterWorkflow != null)
        {
            //调用工作流
            const string key = "Output";
            var input = new WorkflowInput();
            var workflowOutput = await getDefaultFilterWorkflow.InvokeAsync(input);
            if (workflowOutput.Success && input.ContainsKey(key) && input.GetValueOrDefault(key) is CriteriaOperator criteria2)
            {
                if (criteria2 is not null)
                {
                    criteria = criteria2;
                }
            }
        }
        if (criteria is null && examFilter != null)
        {
            criteria = CriteriaOperator.Parse(examFilter.Filter);
        }
        if (criteria is not null)
        {
            criteria = CriteriaOperatorPatcherBase.PatchCriteria(_serviceProvider, criteria);
        }

        return criteria;
    }

    private string ExtendColumnItem(string columnString)
    {
        var jsonArray = JsonNode.Parse(columnString).AsArray();
        if (!jsonArray.Where(x => x["dataField"] != null && x["dataField"].ToString().EqualsIgnoreCase("oid")).Any())
        {
            jsonArray.AddIfNotContains(new JsonObject
            {
                ["dataField"] = "oid",
                ["visible"] = false
            });
        }
        if (!jsonArray.Where(x => x["dataField"] != null && x["dataField"].ToString().EqualsIgnoreCase("reportId")).Any())
        {
            jsonArray.AddIfNotContains(new JsonObject
            {
                ["dataField"] = "reportId",
                ["property"] = "Report==null?null:Report.Oid",
                ["visible"] = false
            });
        }
        return jsonArray.ToString();
    }
}
